/**
 * @file 拖动控制Hook
 * @description 提供元素拖动的通用逻辑，包括拖动处理、位置更新和提示显示
 * @date 2024-08-25
 * 
 * 本组合式函数实现了以下功能：
 * 1. 统一处理鼠标和触摸拖动事件
 * 2. 支持多种拖动类型（主进度、范围开始、范围结束）
 * 3. 提供拖动提示显示功能
 * 4. 自动清理事件监听器，防止内存泄漏
 * 5. 完整的TypeScript类型支持
 * 
 * 该组件从TrackPlayer组件中提取并抽象了拖动逻辑，使其可以被其他需要拖动功能的组件复用。
 */

// Vue相关导入
// @ts-ignore - uni-app环境下Vue导入需要忽略类型检查
import { ref, onUnmounted } from 'vue';
// @ts-ignore - uni-app环境下Vue类型导入需要忽略类型检查
import type { Ref } from 'vue';

/**
 * 拖动类型
 */
export type DragType = 'main' | 'rangeStart' | 'rangeEnd' | null;

/**
 * 提示样式类型
 */
export interface TooltipStyle {
  display: string;
  left: string;
}

/**
 * 拖动控制Hook选项
 */
export interface DragControlOptions<T = any> {
  /** 拖动开始回调函数 */
  onDragStart?: (type: DragType, event: MouseEvent | TouchEvent) => void;
  /** 拖动时回调函数 */
  onDrag?: (percentage: number, type: DragType, containerElement: HTMLElement) => void;
  /** 拖动结束回调函数 */
  onDragEnd?: (type: DragType) => void;
  /** 获取提示内容的函数 */
  getTooltipText?: (type: DragType, percentage: number) => string;
  /** 自定义数据 */
  data?: T;
}

/**
 * 拖动控制Hook
 * @param options 选项配置
 * @returns 拖动相关状态和方法
 */
export function useDragControl(options: DragControlOptions = {}) {
  // 拖动状态
  const isDragging = ref(false);
  const dragType = ref<DragType>(null);
  
  // 提示相关状态
  const tooltipText = ref('');
  const tooltipStyle = ref<TooltipStyle>({
    display: 'none',
    left: '0px'
  });
  
  /**
   * 开始拖动 (鼠标事件)
   * @param event 鼠标事件
   * @param type 拖动类型
   */
  function startDrag(event: MouseEvent, type: DragType): void {
    event.stopPropagation();
    event.preventDefault();
    
    isDragging.value = true;
    dragType.value = type;
    
    // 显示提示
    updateTooltipForElement(event.currentTarget as HTMLElement, type);
    
    // 调用开始拖动回调
    if (options.onDragStart) {
      options.onDragStart(type, event);
    }
    
    // 添加鼠标移动和抬起事件
    document.addEventListener('mousemove', handleDrag);
    document.addEventListener('mouseup', stopDrag);
    
    // 防止拖动时选中文本
    document.addEventListener('selectstart', preventTextSelection);
  }
  
  /**
   * 开始触摸拖动
   * @param event 触摸事件
   * @param type 拖动类型
   */
  function startDragTouch(event: TouchEvent, type: DragType): void {
    event.stopPropagation();
    event.preventDefault();
    
    isDragging.value = true;
    dragType.value = type;
    
    // 显示提示
    updateTooltipForElement(event.currentTarget as HTMLElement, type);
    
    // 调用开始拖动回调
    if (options.onDragStart) {
      options.onDragStart(type, event);
    }
    
    // 添加触摸移动和结束事件
    document.addEventListener('touchmove', handleDragTouch, { passive: false });
    document.addEventListener('touchend', stopDragTouch);
  }
  
  /**
   * 处理拖动 (鼠标移动)
   * @param event 鼠标事件
   */
  function handleDrag(event: MouseEvent): void {
    if (!isDragging.value) return;
    
    event.preventDefault();
    
    // 获取容器元素，应该是拖动元素的父元素
    const containerElement = findContainerElement(event.target as HTMLElement);
    if (!containerElement) return;
    
    const rect = containerElement.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const percentage = Math.max(0, Math.min(100, (x / rect.width) * 100));
    
    // 调用拖动回调
    if (options.onDrag) {
      options.onDrag(percentage, dragType.value, containerElement);
    }
    
    // 更新提示位置
    updateTooltip(containerElement, dragType.value, percentage);
  }
  
  /**
   * 处理触摸拖动
   * @param event 触摸事件
   */
  function handleDragTouch(event: TouchEvent): void {
    if (!isDragging.value) return;
    
    event.preventDefault();
    
    // 获取触摸点
    const touch = event.touches[0];
    
    // 获取容器元素，应该是拖动元素的父元素
    const containerElement = findContainerElement(event.target as HTMLElement);
    if (!containerElement) return;
    
    const rect = containerElement.getBoundingClientRect();
    const x = touch.clientX - rect.left;
    const percentage = Math.max(0, Math.min(100, (x / rect.width) * 100));
    
    // 调用拖动回调
    if (options.onDrag) {
      options.onDrag(percentage, dragType.value, containerElement);
    }
    
    // 更新提示位置
    updateTooltip(containerElement, dragType.value, percentage);
  }
  
  /**
   * 更新提示文本和位置
   * @param containerElement 容器元素
   * @param type 拖动类型
   * @param percentage 百分比位置
   */
  function updateTooltip(containerElement: HTMLElement, type: DragType, percentage: number): void {
    // 获取提示文本
    if (options.getTooltipText) {
      tooltipText.value = options.getTooltipText(type, percentage);
    }
    
    // 查找目标元素来定位提示
    const targetSelector = 
      type === 'main' ? '.timeline-handle' :
      type === 'rangeStart' ? '.range-handle.start' :
      '.range-handle.end';
    
    const targetElement = containerElement.querySelector(targetSelector) as HTMLElement;
    if (targetElement) {
      // 计算提示应该出现的位置
      const elementRect = targetElement.getBoundingClientRect();
      const containerRect = containerElement.getBoundingClientRect();
      const left = elementRect.left - containerRect.left + (targetElement.offsetWidth / 2);
      
      // 更新提示位置
      tooltipStyle.value = {
        display: 'block',
        left: `${left}px`
      };
    }
  }
  
  /**
   * 为给定元素更新提示
   * @param element 拖动元素
   * @param type 拖动类型
   */
  function updateTooltipForElement(element: HTMLElement, type: DragType): void {
    // 获取容器元素
    const containerElement = element.parentElement as HTMLElement;
    if (!containerElement) return;
    
    // 根据类型，计算当前百分比
    let percentage = 0;
    if (options.data) {
      if (type === 'main' && 'progressPercentage' in options.data) {
        percentage = (options.data as any).progressPercentage;
      } else if (type === 'rangeStart' && 'startTimePercentage' in options.data) {
        percentage = (options.data as any).startTimePercentage;
      } else if (type === 'rangeEnd' && 'endTimePercentage' in options.data) {
        percentage = (options.data as any).endTimePercentage;
      }
    }
    
    // 获取提示文本
    if (options.getTooltipText) {
      tooltipText.value = options.getTooltipText(type, percentage);
    }
    
    // 计算提示应该出现的位置
    const elementRect = element.getBoundingClientRect();
    const containerRect = containerElement.getBoundingClientRect();
    const left = elementRect.left - containerRect.left + (element.offsetWidth / 2);
    
    // 更新提示位置
    tooltipStyle.value = {
      display: 'block',
      left: `${left}px`
    };
  }
  
  /**
   * 寻找合适的容器元素
   * @param element 当前元素
   * @returns 容器元素
   */
  function findContainerElement(element: HTMLElement): HTMLElement | null {
    // 尝试在DOM树上向上寻找合适的容器元素
    // 默认使用.timeline作为容器类名
    let current = element;
    while (current && !current.classList.contains('timeline')) {
      current = current.parentElement as HTMLElement;
    }
    return current;
  }
  
  /**
   * 停止拖动 (鼠标)
   */
  function stopDrag(): void {
    if (!isDragging.value) return;
    
    const currentDragType = dragType.value;
    
    // 重置状态
    isDragging.value = false;
    dragType.value = null;
    
    // 隐藏提示
    tooltipStyle.value.display = 'none';
    
    // 调用结束拖动回调
    if (options.onDragEnd) {
      options.onDragEnd(currentDragType);
    }
    
    // 移除事件监听
    document.removeEventListener('mousemove', handleDrag);
    document.removeEventListener('mouseup', stopDrag);
    document.removeEventListener('selectstart', preventTextSelection);
  }
  
  /**
   * 停止触摸拖动
   */
  function stopDragTouch(): void {
    if (!isDragging.value) return;
    
    const currentDragType = dragType.value;
    
    // 重置状态
    isDragging.value = false;
    dragType.value = null;
    
    // 隐藏提示
    tooltipStyle.value.display = 'none';
    
    // 调用结束拖动回调
    if (options.onDragEnd) {
      options.onDragEnd(currentDragType);
    }
    
    // 移除事件监听
    document.removeEventListener('touchmove', handleDragTouch);
    document.removeEventListener('touchend', stopDragTouch);
  }
  
  /**
   * 阻止文本选择
   * @param event 事件对象
   */
  function preventTextSelection(event: Event): void {
    if (isDragging.value) event.preventDefault();
  }
  
  /**
   * 手动显示/隐藏提示
   * @param show 是否显示
   * @param text 提示文本
   * @param left 左边位置
   */
  function showTooltip(show: boolean, text?: string, left?: string): void {
    if (show) {
      tooltipStyle.value = {
        display: 'block',
        left: left || tooltipStyle.value.left
      };
      if (text) {
        tooltipText.value = text;
      }
    } else {
      tooltipStyle.value.display = 'none';
    }
  }
  
  // 组件卸载时清理事件监听
  onUnmounted(() => {
    // 清理可能存在的事件监听
    document.removeEventListener('mousemove', handleDrag);
    document.removeEventListener('mouseup', stopDrag);
    document.removeEventListener('touchmove', handleDragTouch);
    document.removeEventListener('touchend', stopDragTouch);
    document.removeEventListener('selectstart', preventTextSelection);
  });
  
  return {
    // 状态
    isDragging,
    dragType,
    tooltipText,
    tooltipStyle,
    
    // 方法 - 拖动控制
    startDrag,
    startDragTouch,
    stopDrag,
    stopDragTouch,
    
    // 方法 - 提示控制
    showTooltip
  };
} 